<template>
  <n-upload
    action="#"
    :max="data.limit"
    :file-list="data.fileList"
    :default-upload="false"
    class="upload"
    @before-upload="beforeUpload"
    @change="handleChange"
    @remove="handleRemove"
  >
    <n-button>
      <n-icon>
        <FileOutlined />
      </n-icon>
      选择{{ uploadName }}
    </n-button>
  </n-upload>

  <!-- <n-button
    v-if="!autoUpload"
    type="primary"
    :disabled="data.fileList.length === 0"
    style="margin-top: 16px"
    class="btn"
    :loading="loading"
    @click="handleUploadStart"
  >
    <n-icon>
      <UploadOutlined />
    </n-icon>
    开始{{ uploadName }}上传
  </n-button> -->

</template>

<script setup name="UploadVod">
import { FileOutlined, UploadOutlined } from '@vicons/antd'
import { getAuth, refreshAuth } from '@/api/common/upload.js'
import { reactive, ref } from 'vue'

const props = defineProps({
  limit: {
    type: Number,
    default: 10
  },
  autoUpload: {
    type: Boolean,
    default: false
  },
  uploadName: {
    type: String,
    default: '选择文件'
  }
})
const emit = defineEmits(['uploadStatus'])
const loading = ref(false)

const data = reactive({
  limit: props.limit,
  timeout: 600000, // 请求超时时间
  partSize: '', // 分片大小
  parallel: '', // 分片数
  retryCount: '', // 失败重试次数
  retryDuration: '', // 失败重试间隔
  region: 'cn-shanghai', // 配置项
  userId: '224202346013657350', // 阿里云帐号ID

  uploader: null, // 上传实例
  fileList: [], // 上传的文件列表
  uploadFile: [], // 选中的文件列表
  readyFile: {}, // 准备上传的文件列表
  uploaderObject: {} // 上传的实例化对象列表
})

/**
 * @description: 校验文件是否合规
 * @param {*} file
 * @return {*}
 */
const beforeUpload = ({ file }) => {
  if (!file.type.match('video.*')) {
    $message.error('请选择正确的视频')
    return false
  } else {
    const hasSelect = data.fileList.some((item) => item.name === file.name)
    if (!hasSelect) {
      data.uploadFile.push(file.file)
    } else {
      $message.error('您已选择过该文件')
      return false
    }
  }
}

/**
 * @description: 文件发生变化时,过滤不符合条件与重复的文件
 * @param {Array} fileList
 * @return {*}
 */
const handleChange = ({ fileList }) => {
  data.fileList = fileList
  /* 若未实例化过，则实例化上传对象 */
  if (!data.uploader) {
    data.uploader = createUploader()
  }
  const status = fileList.length ? 'ready' : 'no-file'
  emit('uploadStatus', { status, list: data.readyFile })
  handleUploadReady() // 准备上传文件
}

// 删除文件时
const handleRemove = ({ fileList }) => {
  const list = data.uploader.listFiles()
  for (var i = 0; i < list.length; i++) {
    data.uploader.cancelFile(i)
  }
}

/**
 * @description: 创建上传的实例化对象
 * @param {*}
 * @return {*}
 */
const createUploader = () => {
  const uploader = new AliyunUpload.Vod({
    timeout: data.timeout || 60000,
    partSize: data.partSize || 1048576,
    parallel: data.parallel || 5,
    retryCount: data.retryCount || 3,
    retryDuration: data.retryDuration || 2,
    region: data.region,
    userId: data.userId,
    /* 添加文件成功 */
    addFileSuccess: function(uploadInfo) {
      // console.log('addFileSuccess: ' + uploadInfo.file.name)
    },
    // 开始上传
    onUploadstarted: function(uploadInfo) {
      loading.value = true
      if (uploadInfo.videoId) {
        // 如果uploadInfo.videoId存在，调用刷新视频上传凭证接口
        refreshAuth(uploadInfo.videoId).then(res => {
          uploader.setUploadAuthAndAddress(uploadInfo, res.data.uploadAuth, res.data.uploadAddress, res.data.videoId)
          data.videoId = res.data.videoId
        })
      } else {
        const params = {
          title: uploadInfo.file.name,
          fileName: uploadInfo.file.name
        }
        getAuth(params).then(res => {
          uploader.setUploadAuthAndAddress(uploadInfo, res.data.uploadAuth, res.data.uploadAddress, res.data.videoId)
          data.videoId = res.data.videoId
        })
      }
    },

    // 文件上传成功
    onUploadSucceed: function(uploadInfo) {
      const fileName = uploadInfo.file.name
      data.fileList.forEach((item) => {
        if (item.name === fileName) {
          data.readyFile.videoUrl = '/' + uploadInfo.object
          data.readyFile.videoId = uploadInfo.videoId
        }
      })
    },
    // 文件上传失败
    onUploadFailed: function(uploadInfo, code, message) {
      // console.log('onUploadFailed: file:' + uploadInfo.file.name + ',code:' + code + ', message:' + message)
    },

    // 取消文件上传
    onUploadCanceled: function(uploadInfo, code, message) {
      // console.log('Canceled file: ' + uploadInfo.file.name + ', code: ' + code + ', message:' + message)
    },

    // 文件上传进度，单位：字节, 可以在这个函数中拿到上传进度并显示在页面上
    onUploadProgress: function(uploadInfo, totalSize, progress) {
      // console.log("onUploadProgress:file:" + uploadInfo.file.name + ", fileSize:" + totalSize + ", percent:" + Math.ceil(progress * 100) + "%")
      const progressPercent = Math.ceil(progress * 100)
      const fileName = uploadInfo.file.name
      data.fileList.forEach((item) => {
        if (item.name === fileName) {
          item.status = progressPercent === 100 ? 'success' : 'uploading'
          item.percent = progressPercent
        }
      })
    },

    // 上传凭证超时
    onUploadTokenExpired: function(uploadInfo) {
      console.log('onUploadTokenExpired', uploadInfo)
      refreshAuth(uploadInfo.videoId).then(res => {
        uploader.resumeUploadWithAuth(uploadInfo, res.data.uploadAuth, res.data.uploadAddress, res.data.videoId)
      })
    },

    // 全部文件上传结束
    onUploadEnd: function(uploadInfo) {
      // console.log('onUploadEnd: uploaded all the files', uploadInfo)
      loading.value = false
      emit('uploadStatus', { status: 'success', list: data.readyFile, videoIds: data.videoId })
    }
  })
  return uploader
}

/**
 * @description: 新建文件到实例对象中
 * @param {*}
 * @return {*}
 */
const handleUploadReady = () => {
  data.uploadFile.forEach((item, index) => {
    /* 是否已经新建过该文件 */
    if (!Object.keys(data.readyFile).includes(item.uid)) {
      const obj = {
        name: item.name,
        videoUrl: '',
        videoId: ''
      }
      data.readyFile = obj
      data.uploader.addFile(item, null, null, null, '{"Vod":{}}')
    }
  })
  if (props.autoUpload) { // 判断是否自动上传
    handleUploadStart()
  }
}

/**
 * @description: 开始上传文件
 * @param {*}
 * @return {*}
 */
const handleUploadStart = () => {
  if (data.uploader !== null) {
    data.uploader.startUpload()
    emit('uploadStatus', { status: 'uploading', list: data.readyFile })
    return data.readyFile
  }
}

defineExpose({ data, handleUploadStart })

</script>

<style lang="scss" scoped>
.upload {
  list-style: none;
  padding: 10px 20px;
}

.upload .upload-item__name {
  margin-bottom: 5px;
}

.btn {
  // width: 120px;
  margin-left: calc(50% - 60px);
  margin-top: 10px;
  margin-bottom: 30px;
}
</style>
